해당 편에서는 SSR 구현과정 중 프로젝트 시작 및 CSR 구현을 다룹니다.
SSR 구현에 CSR이 왜 필요한지 의문을 가질 수 있습니다.
CSR이 필요한 이유는 SPA기반 SSR은 CSR 앱을 이용해 서버에서 렌더링하는 것이기 때문입니다.
또한 SPA기반 SSR은 클라이언트가 페이지에 최초 접속시, 정확히 말하자면 SSR을 담당하는 서버에 요청을 보내는 과정에서만 SSR이 이루어지고,
그 이후 렌더링 과정은 CSR로 이루어지기 때문입니다.
해당 과정 중 많은 부분을 출처의 실전 리액트 프로그래밍 (이재승 저)책을 참고하여 작성하였습니다. 문제가 될 시 wnsgur6311@gmail.com으로 연락부탁드립니다.
패키지 설치
npm init -y
npm i react react-dom
# 바벨
npm i -D @babel/core @babel/preset-env @babel/preset-react
# 웹팩
npm i -D webpack webpack-cli babel-loader html-webpack-plugin webpack-dev-server
npm i react react-dom
해당 글에서는 CSR을 React에 의존해 구현하므로 React 사용에 필요한 패키지를 설치합니다.npm i -D @babel/core @babel/preset-env @babel/preset-react
해당 글에서는 ES6 이상의 문법을 사용할 예정이므로@babel/preset-env
프리셋을 사용합니다.
또한 React의JSX
문법을 사용하기 위해@babel/preset-react
프리셋을 사용합니다.npm i -D webpack webpack-cli babel-loader html-webpack-plugin webpack-dev-server
모듈 번들러로써 Webpack을 사용합니다. 이를 위해webpack
을 사용하고,cli
로webpack
을 사용하기 위해webpack-cli
도 사용합니다.
번들 과정에서 Babel을 사용하기 위해babel-loader
도 설치합니다.
번들된 파일을 수동으로 html 파일에 넣어주는 과정을 피하기 위해html-webpack-plugin
을 사용합니다.
개발 서버를 사용하기 위해webpack-dev-server
도 사용합니다.
위 내용이 어려우신 분들은 제 글 중 [환경설정] CRA환경 구현해보기를 읽어보시거나 트랜스파일, 모듈 번들러등의 프론트엔드 개발환경을 공부해보시는 것을 추천드립니다.
모든 디렉토리 패스는 프로젝트 루트를 기준으로 합니다.
index.html 작성
-
template/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test-ssr</title> </head> <body> <div id="root"></div> </body> </html>
컴포넌트 작성
예제에 사용될 컴포넌트들을 작성합니다.
-
src/Home.js
import React from 'react'; function Home() { return <div> <h3>This is home page</h3> </div> } export default Home;
-
src/About.js
import React from 'react'; function About() { return ( <div> <h3>This is about page</h3> </div> ) } export default About;
-
src/App.js
import React, { useState, useEffect } from 'react'; import Home from "./Home"; import About from "./About"; function App({ page: initialPage }) { const [page, setPage] = useState(initialPage); useEffect(() => { window.onpopstate = event => { setPage(event.state); } },[]); function onChangePage(e) { const newPage = e.target.dataset.page; window.history.pushState(newPage, '', `/${newPage}`); setPage(newPage); }; const PageComponent = page === 'home' ? Home : About; return ( <div> <button data-page="home" onClick={onChangePage}> Home </button> <button data-page="about" onClick={onChangePage}> About </button> <PageComponent /> </div> ) } export default App;
-
src/index.js
import React from 'react'; import ReactDom from 'react-dom'; import App from "./App"; ReactDom.render(<App page="home" />, document.getElementById('root'));
아래 내용에 나오는 Webpack이나 Babel에 관한 내용은 [환경설정] CRA환경 구현해보기을 읽으시면 대부분 이해하실 수 있습니다.
바벨 설정
-
babel.config.js
const presets = ['@babel/preset-react', '@babel/preset-env']; const plugins = []; module.exports = { presets, plugins };
웹팩 설정
-
webpack.config.js
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: "[name].[chunkhash].js", path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader', } ] }, plugins: [ new HtmlWebpackPlugin({ template: "./template/index.html" }) ], mode: "production", devServer: { historyApiFallback: true, } }
- historyApiFallback
컴포넌트 구현에서 쓰인 HTML5 history API을 사용하기 위한 설정입니다.
실행 확인
-
실행 명령어
webpack serve
마무리
이번 편에서는 프로젝트 시작 및 CSR 구현을 하였습니다.
다음 편에서는 SSR용 서버를 구현하고 Hydration
에 대해서 알아보겠습니다.